#include "asynctcpsocketimpl.h"
#include "iooperationimpl.h"
#include "ioimpl/iothreadpool.h"



CAsyncTcpSocketImpl::CAsyncTcpSocketImpl()
{
	m_tcp = new io_tcp_i;
	memset(m_tcp, 0, sizeof(io_tcp_i));
	m_stream = new io_streambase_t;
	memset(m_stream, 0, sizeof(io_streambase_t));

	m_ulRecvBufLen			=	8 * 1024;
	m_ulSendBufLen			=	8 * 1024;
	m_ulConnectTimeoutSec	=	5;

}
CAsyncTcpSocketImpl::~CAsyncTcpSocketImpl()
{
    
}
//////////////////////////////////////////////////////////////////////////
std_method_impl CAsyncTcpSocketImpl::ReadIo(IIoOperation* pOperation)
{
	HRESULT		hr = S_OK;
	retrtpv(pOperation, E_FAIL)
	retrtpv(m_stream, E_FAIL);

	pOperation->SetOpType(OP_TCPSOCKET_RECV);
	m_stream->io.pdata = pOperation;
	ULONG pIoStartPos = 0;
	ULONG pIoExpectBytes = 0;
	pOperation->GetIoParam(&pIoStartPos, &pIoExpectBytes);
	m_stream->io.stream.pReadPtr = pOperation->GetIo(pIoStartPos);
	m_stream->io.stream.ulReadLen = m_ulRecvBufLen;
	m_stream->thread = pOperation->GetMultiThread();

	if (!io_streambase_read(m_stream, pIoExpectBytes))
		return hr;
	return E_FAIL;
}
std_method_impl CAsyncTcpSocketImpl::WriteIo(IIoOperation* pOperation)
{
	HRESULT		hr = S_OK;
	retrtpv(pOperation, E_FAIL)
	retrtpv(m_stream, E_FAIL);

	pOperation->SetOpType(OP_TCPSOCKET_SEND);
	m_stream->io.pdata = pOperation;
	ULONG pIoStartPos		= 0;
	ULONG pIoExpectBytes	= 0;
	pOperation->GetIoParam(&pIoStartPos,&pIoExpectBytes);
	m_stream->io.stream.pWritePtr = pOperation->GetIo(pIoStartPos);
	m_stream->io.stream.ulWriteLen = m_ulSendBufLen;
	m_stream->thread = pOperation->GetMultiThread();

	if (!io_streambase_write(m_stream, pIoExpectBytes))
		return hr;
	return E_FAIL;
}
std_method_impl CAsyncTcpSocketImpl::ReadAllIo(IIoOperation* pOperation)
{
	HRESULT		hr = S_OK;
	retrtpv(pOperation, E_FAIL)

	return hr;
}
std_method_impl CAsyncTcpSocketImpl::WriteAllIo(IIoOperation* pOperation)
{
	HRESULT		hr = S_OK;
	retrtpv(pOperation, E_FAIL)

	return hr;
}
std_method_impl CAsyncTcpSocketImpl::ConnectIo(IIoOperation* pOperation)
{
	HRESULT		hr = S_OK;
	retrtpv(pOperation, E_FAIL)

	pOperation->SetOpType(OP_TCPSOCKET_CONNECT);
	m_tcp->tcp_fun_cb = StreamOpenProc;
	int ires = io_tcp_connect(m_tcp, pOperation, pOperation->GetAddress(), pOperation->GetConPort(),m_ulConnectTimeoutSec);

	return ires == 1 ? S_OK : E_FAIL;
}
std_method_impl CAsyncTcpSocketImpl::AcceptConnect(IIoOperation* pOperation)
{
	HRESULT		hr = S_OK;

	return hr;
}
std_method_impl CAsyncTcpSocketImpl::CloseIo()
{
	HRESULT		hr = S_OK;

	if (m_socketFd != INVALID_SOCKET) 
	{
#if (TARGET_OS == OS_WINDOWS)
		closesocket(m_socketFd);
#elif (TARGET_OS == OS_POSIX)
		close(m_socketFd);
#endif
	}

	m_socketFd = INVALID_SOCKET;

	io_streambase_close(m_stream);
	io_tcp_uninit(m_tcp);

	return hr;
}
std_method_impl CAsyncTcpSocketImpl::OpenIo()
{
	HRESULT		hr = S_OK;

	m_socketFd = -1;
	
	m_socketFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

	if (m_socketFd == INVALID_SOCKET) {
		return E_FAIL;
	}

	io_tcp_init(m_tcp);
	io_tcp_open(m_tcp,m_socketFd);

	return hr;
}
std_method_impl CAsyncTcpSocketImpl::BindIo()
{
	retrtpv(m_stream, E_FAIL);
	io_streambase_init(m_stream, m_tcp,5,5);
	m_stream->stream_fun_writecb	= StreamWriteProc;
	m_stream->stream_fun_readcb		= StreamReadProc;
	m_stream->stream_fun_eventcb	= StreamEventProc;
	return S_OK;
}
std_method_type_impl(os_sock_t) CAsyncTcpSocketImpl::GetSocket()
{
	return m_socketFd;
}
std_method_impl CAsyncTcpSocketImpl::BindSocket(os_sock_t sock)
{

	if (m_socketFd != INVALID_SOCKET) 
	{

#if (TARGET_OS == OS_WINDOWS)
		closesocket(m_socketFd);
#elif (TARGET_OS == OS_POSIX)
		close(m_socketFd);
#endif
	}

	m_socketFd = sock;

	return S_OK;
}
std_method_impl CAsyncTcpSocketImpl::SetReuseAddr(bool bstart)
{
	HRESULT		hr	=	S_OK;
	
	return hr;
}
std_method_impl CAsyncTcpSocketImpl::SetNoDelay(bool bstart)
{
	HRESULT		hr	=	S_OK;

	return hr;
}
std_method_impl CAsyncTcpSocketImpl::SetLinger(bool bstart)
{
	HRESULT		hr	=	S_OK;

	return hr;
}
std_method_impl CAsyncTcpSocketImpl::SetKeepalive(bool bstart)
{
	HRESULT		hr	=	S_OK;

	return hr;
}
std_method_impl CAsyncTcpSocketImpl::SetCork(bool bstart)
{
	HRESULT		hr	=	S_OK;
	int set = 0;
	set = (bstart == true? 1 : 0);

#if (TARGET_OS != OS_WINDOWS)
	setsockopt(m_socketFd, SOL_TCP, TCP_CORK, (void *)&set, sizeof(int));
#endif

	return hr;
}
std_method_impl CAsyncTcpSocketImpl::SetNoSigPipe(bool bstart)
{

	HRESULT		hr	=	S_OK;

	int set = 0;
	set = (bstart == true? 1 : 0);

	//unix no found MSG_NOSIGNAL, but have SO_NOSIGPIPE
	
#if (TARGET_OS != OS_WINDOWS)

#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
	#define MSG_NOSIGNAL SO_NOSIGPIPE
#endif
	setsockopt(m_socketFd, SOL_SOCKET, MSG_NOSIGNAL, (void *)&set, sizeof(int)); 
#endif

	return hr;
}
std_method_impl CAsyncTcpSocketImpl::SetNonblock(bool bstart)
{
	return S_OK;
}
std_method_impl CAsyncTcpSocketImpl::SendBufLen(ULONG size)
{
	retrtnpv(m_socketFd == INVALID_SOCKET, E_FAIL);
	int nSendBuf = size * 1024;
	m_ulSendBufLen = nSendBuf;
	setsockopt(m_socketFd, SOL_SOCKET, SO_SNDBUF, (const char*)&nSendBuf, sizeof(int));
	return S_OK;
}
std_method_impl CAsyncTcpSocketImpl::RecvBufLen(ULONG size)
{
	retrtnpv(m_socketFd == INVALID_SOCKET, E_FAIL);
	int nRecvBuf = size * 1024;
	m_ulRecvBufLen = nRecvBuf;
	setsockopt(m_socketFd, SOL_SOCKET, SO_RCVBUF, (const char*)&nRecvBuf, sizeof(int));
	return S_OK;
}
std_method_impl CAsyncTcpSocketImpl::SendTimeOut(int sec)
{
	retrtnpv(m_socketFd == INVALID_SOCKET, E_FAIL);
	struct timeval timeout;
	timeout.tv_sec = sec;
	timeout.tv_usec = 0;
	socklen_t len = sizeof(timeout);
	setsockopt(m_socketFd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, len);
	retrtpv(m_stream, E_FAIL);
	io_streambase_wrtie_timeout(m_stream, sec);
	return S_OK;
}
std_method_impl CAsyncTcpSocketImpl::RecvTimeOut(int sec)
{
	retrtnpv(m_socketFd != INVALID_SOCKET, E_FAIL);
	struct timeval timeout;
	timeout.tv_sec = sec;
	timeout.tv_usec = 0;
	socklen_t len = sizeof(timeout);
	setsockopt(m_socketFd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, len);
	retrtpv(m_stream, E_FAIL);
	io_streambase_read_timeout(m_stream, sec);
	return S_OK;
}
std_method_impl CAsyncTcpSocketImpl::ConnectTimeOut(int sec)
{	
	//
	m_ulConnectTimeoutSec = sec;
	return S_OK;
}
std_method_impl CAsyncTcpSocketImpl::SendLoWat(int size)
{
	retrtnpv(m_socketFd != INVALID_SOCKET, E_FAIL);
	return S_OK;
}
std_method_impl CAsyncTcpSocketImpl::RecvLoWat(int size)
{
	retrtnpv(m_socketFd != INVALID_SOCKET, E_FAIL);
	return S_OK;
}

void CAsyncTcpSocketImpl::StreamOpenProc(io_tcp_i *pData, int iStatus)
{
	IIoOperation* pOperation = static_cast<IIoOperation*>(pData->io.pdata);

	switch (pOperation->GetOpType())
	{
	case OP_TCPSOCKET_CONNECT:
		{

			ERROR_CODE errorcode = IO_TCP_CONNECTED != iStatus ? OP_OPENFDRROR : 0;
			pOperation->SetResult(errorcode, 0);
		}
		break;

	}

	pOperation->Post();
	
}
void CAsyncTcpSocketImpl::AsyncWokerProc(void *pData)
{
	IIoOperation* pOperation = static_cast<IIoOperation*>(pData);
	pOperation->Post();
}
void CAsyncTcpSocketImpl::StreamWriteProc(io_streambase_t* pData, unsigned long ulen)
{
	IIoOperation* pOperation = static_cast<IIoOperation*>(pData->io.pdata);
	pOperation->SetResult(0, ulen);
	pOperation->Post();
}
void CAsyncTcpSocketImpl::StreamReadProc(io_streambase_t* pData, unsigned long ulen)
{
	IIoOperation* pOperation = static_cast<IIoOperation*>(pData->io.pdata);
	pOperation->SetResult(0, ulen);
	pOperation->Post();
}
void CAsyncTcpSocketImpl::StreamEventProc(io_streambase_t* pData, short what)
{
	IIoOperation* pOperation = static_cast<IIoOperation*>(pData->io.pdata);

	if (what & STREAM_EVENT_EOF) {
		pOperation->SetResult(OP_EOF,0);
	}
	else if (what & STREAM_EVENT_TIMEOUT) {
		pOperation->SetResult(OP_TIMEOUT, 0);
	}
	else if (what & STREAM_EVENT_ERROR) {
		pOperation->SetResult(OP_ERROR, 0);
	}
	else if (what & STREAM_EVENT_UNKNOWN) {
		pOperation->SetResult(OP_EXCEPTION, 0);
	}

	pOperation->Post();
}
